package controler;

import java.awt.Component;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Iterator;
import java.util.Stack;

import main.Test1;
import model.ModelConstraint;
import model.ModelPlayer;
import model.ModelTile;
import modelImp.Pawn;
import modelImp.Player;
import modelImp.Tile;

import ressources.Constant;

import view.BoardPanel;
import view.GamePanel;
import view.PawnComponent;
import view.BoardPanel.DrawingPane;
import view.TileComponent.PositionPoint;
import view.TileComponent;

public class Game implements ActionListener, MouseMotionListener, MouseListener{
	InitGame init;
	BoardPanel boardpanel=null;
	GamePanel gamepanel=null;
	Stack<ModelTile> stack;
	Iterator<ModelPlayer> iterator;
	Player currentPlayer = null;
	boolean isTilePop = false, isTilePut = false, isPawnPut = false, isPawnPop=false;

	/*
	 * On prend un boardpanel,le gamepanel on fait le lien avec les ecouteur
	 * A CONDITION que l'initialisation soit bien faite :)
	 * 
	 */
	public Game(BoardPanel bpanel,GamePanel gpanel){
		try {
			this.init = InitGame.getInstance();
			this.stack = init.board.getTileStack();
			
			this.boardpanel = bpanel;
			TileComponent firstTile =new TileComponent(init.board.getFirstTile());
			firstTile.setLocation(boardpanel.getWidth()/2,boardpanel.getHeight()/2);
			boardpanel.drawingPane.add(firstTile);
			this.gamepanel = gpanel;
			this.gamepanel.btnPioche.piocheButton.addActionListener(this);
			this.gamepanel.btnPioche.piocheButton.setActionCommand(Constant.key_poptile);
			this.boardpanel.drawingPane.addMouseMotionListener(this);
			this.boardpanel.drawingPane.addMouseListener(this);
			this.gamepanel.btnContinu.setActionCommand(Constant.key_validate);
			this.gamepanel.btnContinu.addActionListener(this);
			this.gamepanel.btnPawn.pawnButton.setActionCommand(Constant.key_poppawn);
			this.gamepanel.btnPawn.pawnButton.addActionListener(this);
			
			
			this.gamepanel.btnPioche.cardLeftLabel.setText(setTilesLabel(stack.size()));
			
			
			iterator = InitGame.players.iterator();
			this.nextPlayer(); 
					
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	private void popTile(){
		if(!stack.empty() && !isTilePop){
			boardpanel.currentTile = new TileComponent((Tile) stack.pop());
			isTilePop = true;
		}
	}
	
	
	/*
	 * Validate : 
	 * Calcul du score, mise à null des tuiles, et passage au joueurs suivant
	 */
	private void validate(){
		isTilePop = false; isTilePut = false; isPawnPut = false; isPawnPop =false;
		boardpanel.currentTile.removePositions();
		boardpanel.currentTile = null;
		boardpanel.repaint();
		nextPlayer();	
	}
	
	private void putTile(Point p){
		Tile[] neighbors = this.getNeighbors(p);
		if(isTilePop && !isTilePut && boardpanel.currentTile.getTile().canPutTile(neighbors))
		{
			// replace neighbors
			boardpanel.currentTile.getTile().setNeighbors(neighbors);			
			boardpanel.drawingPane.add(boardpanel.currentTile);
			updateDrawingPaneSize();
			isTilePut = true;
		}
	}
	
	
	private void moveAgain(Point p){
		if(!isPawnPop && !isPawnPut && isTilePop && isTilePut && boardpanel.drawingPane.getComponentAt(p) == boardpanel.currentTile)
			isTilePut = false;
	}
	
	private void rotateTile(){
		if(isTilePop && !isTilePut)
		boardpanel.currentTile.rotate();
		boardpanel.repaint();
	}
	
	private void popPawn(){
		// Tuile posé, et on veut prendre pion
		if(isTilePut && !isPawnPop && !isPawnPut){
			int size = this.currentPlayer.getPawnSize();
			if(size>0)
			{		
				for(int i=0;i<boardpanel.currentTile.getComponentCount();i++)
				{
					if(boardpanel.currentTile.getComponent(i) instanceof PositionPoint )
					((PositionPoint)boardpanel.currentTile.getComponent(i)).addMouseListener(this);
				}
				isPawnPop = true;
			}
		}
		// Tuile posé, on veut reposer le pion
		else if(isTilePut && isPawnPop && !isPawnPut){
			//System.out.println("Tuile posé, on veut reposer le pion");
			isPawnPop =false;
		}
		else{
		//	System.out.println("On ne peut pas");
		}
		
	}
	
	
	@Override
	public void actionPerformed(ActionEvent e) {
		// POP TILE
		if(e.getActionCommand().equals(Constant.key_poptile)){
			popTile();
		}
		// VALIDATE 
		if(e.getActionCommand().equals(Constant.key_validate)){
			validate();
		}
		
		// POP PAWN 
		if(e.getActionCommand().equals(Constant.key_poppawn)){
			popPawn();
		}
	}
	
	@Override
	public void mouseMoved(MouseEvent e) {
		if(e.getSource() instanceof DrawingPane)
		{
			if(!isTilePut && isTilePop){
				DrawingPane dp = (DrawingPane) e.getSource();
				boardpanel.currentTile.setLocation(e.getPoint());
				dp.repaint();			
			
			}
			
			
		}
		if(e.getSource() instanceof TileComponent)
		{
		}
		
	}
	
	private Tile[] getNeighbors(Point currentPoint){
		Tile[] neighbors = new Tile[4];
		Component[] comp = new Component[4];
		comp[0] = boardpanel.drawingPane.getComponentAt(new Point(currentPoint.x,currentPoint.y - 78));
		comp[1]= boardpanel.drawingPane.getComponentAt(new Point(currentPoint.x,currentPoint.y + 78));
		comp[2] = boardpanel.drawingPane.getComponentAt(new Point(currentPoint.x+78,currentPoint.y));
		comp[3]= boardpanel.drawingPane.getComponentAt(new Point(currentPoint.x-78,currentPoint.y));
		for(int i=0;i<4;i++){
			if(comp[i] instanceof TileComponent){
				neighbors[i] = ((TileComponent)comp[i]).getTile();
				
			}
			else{
				neighbors[i] = null;
			}
		}
		return neighbors;
	}
	
	@Override
	public void mousePressed(MouseEvent e) {
		if(e.getButton()==MouseEvent.BUTTON1){
			// PutPawn
			if(e.getSource() instanceof PositionPoint)
			{
				if(isPawnPop && !isPawnPut && isTilePut)
				{
					putPawn((PositionPoint)e.getSource());
					System.out.println("1-Clique sur une position");
				}
			}
			else if(e.getSource() instanceof DrawingPane)
			{
				// Put a tile
				if(!isTilePut)
					putTile(e.getPoint());
				// Move (again)  Tile
				else{
					moveAgain(e.getPoint());
				}						
			}
		}
		// Rotate Tile
		else{
			rotateTile();
		}	
		this.gamepanel.btnPioche.cardLeftLabel.setText(setTilesLabel(stack.size()));
	}
	
	
	
    private void putPawn(PositionPoint pp) {
    	pp.position.setPawn(this.currentPlayer.removePawn(this.currentPlayer.getPawnSize()-1));
    	isPawnPut = true;
		
	}

	public void nextPlayer(){
		if(iterator.hasNext())
			this.currentPlayer = (Player) iterator.next();
		else {
			iterator = InitGame.players.iterator();
			this.nextPlayer();
		}
		Test1.main.messages.mesages.append("\nC'est le tour de " +currentPlayer.getName()+" pour jouer.");
	}
	
	
	public String setTilesLabel(int numberTiles){
		String numberTilesToString;
		String texteLabel;
		numberTilesToString= String.valueOf(numberTiles);
		texteLabel ="Reste " +  numberTilesToString + " tuiles!";
		return texteLabel;		
	}
	
	private void updateDrawingPaneSize() {
		int W = boardpanel.currentTile.getWidth();
        int H = boardpanel.currentTile.getHeight();
        Rectangle rect=null;

        int x = boardpanel.currentTile.getX()+Constant.WIDTH_TILE;
        int y = boardpanel.currentTile.getY()+Constant.WIDTH_TILE;
        
        // When we put a tile on the first row or first column, we resize the panel and translate all component   
        // first row
        if((x>=0 && x<=boardpanel.drawingPane.getWidth()) && (y>=0 && y<=Constant.WIDTH_TILE))           
        {
        	((DrawingPane)boardpanel.drawingPane).translateAllComponent(0,Constant.WIDTH_TILE);
        	this.boardpanel.area.height += Constant.WIDTH_TILE;
        	
        }
        //first column
        if (y>=0 && y<=boardpanel.drawingPane.getHeight() && (x>=0 && x<=Constant.WIDTH_TILE)) {
        	((DrawingPane)boardpanel.drawingPane).translateAllComponent(Constant.WIDTH_TILE,0);
        	this.boardpanel.area.width += Constant.WIDTH_TILE;
        }
        if (x < 0) x = 0;
        if (y < 0) y = 0;
        rect = new Rectangle(x, y, W, H);
        this.boardpanel.drawingPane.scrollRectToVisible(rect);
        
        int this_width = (x + W + 2);
        if (this_width > this.boardpanel.area.width) {
        	this.boardpanel.area.width = this_width; 
        }
        int this_height = (y + H + 2);
        if (this_height > this.boardpanel.area.height) {
            this.boardpanel.area.height = this_height; 
        }
        
        //if(board.tile.get)

        this.boardpanel.drawingPane.setPreferredSize(this.boardpanel.area);

        //Let the scroll pane know to update itself and its scrollbars.
        this.boardpanel.drawingPane.revalidate();
        this.boardpanel.drawingPane.repaint();
		
	}
	@Override
	public void mouseReleased(MouseEvent arg0) {}
	@Override
	public void mouseClicked(MouseEvent arg0) {}
	@Override
	public void mouseDragged(MouseEvent arg0) {}
	@Override
	public void mouseEntered(MouseEvent arg0) {}
	@Override
	public void mouseExited(MouseEvent arg0) {}
	
	

}
